﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using Newtonsoft.Json;

namespace DSPCalculator.mechanics
{
    public class Calculator
    {
        public Calculator()
        {
            Stream st = File.Open("Storage/itemInfo.json", FileMode.Open);
            StreamReader sr = new StreamReader(st);
            string data = sr.ReadToEnd();
            items = JsonConvert.DeserializeObject<List<ItemInfo>>(data);
        }
        private List<ItemInfo> items;
        private Tree tree;
        public void Visualize(Bitmap b,string itemName,decimal nps,float sheer)
        {
            Visualizer v = new Visualizer(b);
            CreateTree(itemName, nps);
            v.Draw(tree,sheer);
        }
        public void CreateTree(string itemName,decimal needSpeed)
        {
            tree = new Tree();
            tree.nodes = new List<Node>();
            Node root = new Node(itemName, needSpeed, items, 0);
            tree.nodes.Add(root);
            tree.root = root;
            int curLayer = 0;
            do
            {
                bool isBasic = true;
                List<Node> targets= tree.nodes.FindAll(x => x.layer == curLayer);
                for(int i = 0; i < targets.Count; i++)
                {
                    string ing = targets[i].item.ingredients;
                    if (ing == "")
                        continue;
                    else
                        isBasic = false;
                    string[] types = ing.Split('+');
                    foreach(string type in types)
                    {
                        string itemN = type.Split('*')[1];
                        decimal num = decimal.Parse(type.Split('*')[0]);
                        Node n = new Node(itemN, num * targets[i].needSpeed, items, curLayer + 1);
                        targets[i].branches.Add(n);
                        tree.nodes.Add(n);
                    }
                }
                retry:
                targets = tree.nodes.FindAll(x => x.layer == curLayer);
                for (int i = 0; i < targets.Count - 1; i++)
                {
                    for (int j = i + 1; j < targets.Count; j++)
                    {
                        if (targets[i].item == targets[j].item)
                        {
                            Merge(targets[i], targets[j]);
                            goto retry;
                        }
                    }
                }
                if (isBasic)
                    break;
                curLayer++;
            }
            while (true);
            tree.maxLayer = curLayer;


            //for (int i = 0; i <= tree.maxLayer - 1;)
            //{
            //    bool found = false;
            //    List<Node> y1 = tree.nodes.FindAll(x => x.layer == i);
            //    List<Node> y2 = tree.nodes.FindAll(x => x.layer == i + 1);
            //    for (int j = 0; j < y1.Count; j++)
            //    {
            //        Node m = y2.Find(x => x.item == y1[j].item);
            //        if (m != null)
            //        {
            //            Merge(m, y1[j]);
            //            found = true;
            //        }
            //    }
            //    if (!found)
            //        i++;
            //}
            for (int i = 0; i <= tree.maxLayer - 1;)
            {
                bool found = false;
                List<Node> y1 = tree.nodes.FindAll(x => x.layer == i);
                for (int k = i + 1; k <= tree.maxLayer;)
                {
                    bool found2 = false;
                    List<Node> y2 = tree.nodes.FindAll(x => x.layer == k);
                    for (int j = 0; j < y1.Count; j++)
                    {
                        Node m = y2.Find(x => x.item == y1[j].item);
                        if (m != null)
                        {
                            Merge(m, y1[j]);
                            found = true;
                        }
                    }
                    if (!found2)
                        k++;
                }
                if (!found)
                    i++;
            }
        }
        private void Merge(Node main,Node sub)
        {
            main.AddBy(sub);
            List<Node> needCorrection = tree.nodes.FindAll(x => x.branches.Contains(sub));
            for(int i = 0; i < needCorrection.Count; i++)
            {
                needCorrection[i].branches.Remove(sub);
                needCorrection[i].branches.Add(main);
            }
            tree.nodes.Remove(sub);
        }
    }
    public class Tree
    {
        public List<Node> nodes;
        public int maxLayer;
        public Node root;
        public List<List<Node>> layers;
        public void refreshLayer()
        {

        }
    }
    public class Node
    {
        public ItemInfo item;
        public decimal machineNum;
        public decimal needSpeed;//每秒几个
        public int layer;
        public List<Node> branches;
        public Node(string itemName,decimal needSpeed,List<ItemInfo> items,int layer)
        {
            this.layer = layer;
            this.needSpeed = needSpeed;
            item = items.Find(x => x.name == itemName);
            this.machineNum = needSpeed * item.time;
            branches = new List<Node>();
        }
        public override string ToString()
        {
            return this.item.name;
        }
        public void AddBy(Node n)
        {
            needSpeed += n.needSpeed;
            machineNum += n.machineNum;
        }
    }
    public class ItemInfo
    {
        public string name;
        public string ingredients;
        public string machine;
        public decimal time;
    }
}
